from kubernetes import config as kube_config, client
from typing import Optional
from logging import Logger
import socket
import time
import sys

from common import config

try:
    kube_config.load_kube_config()
except kube_config.config_exception.ConfigException:
    try:
        kube_config.load_incluster_config()
    except kube_config.config_exception.ConfigException:
        raise RuntimeError(
            "Failed to load Kubernetes configuration. Ensure you are running this code inside a Kubernetes cluster or have a valid kubeconfig file.")

apps_api:client.AppsV1Api = client.AppsV1Api()
core_api: client.CoreV1Api = client.CoreV1Api()
custom_obj_api: client.CustomObjectsApi = client.CustomObjectsApi()
networking_v1_api: client.NetworkingV1Api = client.NetworkingV1Api()

_cluster_domain = None


def get_k8s_cluster_domain(logger: Optional[Logger], namespace: str = "kube-system") -> str:
    global _cluster_domain

    if _cluster_domain:
        return _cluster_domain

    if config.K8S_CLUSTER_DOMAIN:
        _cluster_domain = config.K8S_CLUSTER_DOMAIN
        if logger:
            logger.info(f"Using K8S_CLUSTER_DOMAIN from environment: {_cluster_domain}")
        return _cluster_domain

    for _ in range(config.AUTO_DISCOVER_K8S_CLUSTER_DOMAIN_MAX_RETRIES):
        try:
            ip = next(
                filter(
                    lambda ip: ip,
                    map(lambda service: service.spec.cluster_ip, core_api.list_namespaced_service(namespace).items)
                )
            )

            if ip:
                fqdn = socket.gethostbyaddr(ip)[0]
                [_, _, _, _cluster_domain] = fqdn.split(".")
                if logger:
                    logger.info(f"Discovered K8S_CLUSTER_DOMAIN: {_cluster_domain}")
                return _cluster_domain
        except Exception as e:
            if logger:
                logger.warning(f"Failed to discover K8S_CLUSTER_DOMAIN: {e}")
            time.sleep(2)

    if logger:
        logger.error(
            f"Failed to discover K8S_CLUSTER_DOMAIN after {config.AUTO_DISCOVER_K8S_CLUSTER_DOMAIN_MAX_RETRIES} retries.")
    else:
        print(
            f"Failed to discover K8S_CLUSTER_DOMAIN after {config.AUTO_DISCOVER_K8S_CLUSTER_DOMAIN_MAX_RETRIES} retries.")
    sys.exit(1)
